package test.testnew;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class MyTestNew
{

  private static Map< Integer, Long > ObjectHashCodeThreadMap = new HashMap< Integer, Long >();
  private static Map< Object, Long > ObjectThreadMap       = new HashMap< Object, Long >();

  private static final int LOOP_TIMES = 10000;
  private static final int HOLD_TIME = 5;
  private static final int THREAD_NUM = 1000;
  private static final int THREAD_TIME_SPAN = 5;
  
  private static int hashCodeDuplicates = 0;
  private static int referenceDuplicates = 0;
  
  private static abstract class T extends Thread
  {
    @Override
    public void run()
    {
      for ( int i = 0; i < LOOP_TIMES; i++ )
      {
        Object obj = new Object();

        handleObj( obj );
        Random r = new Random();
        try
        {
          Thread.sleep( r.nextInt( HOLD_TIME ) );
        }
        catch ( InterruptedException e )
        {
        }
      }
    }

    protected abstract void handleObj( Object obj );
  }

  //check with hashcode
  private static class T1 extends T
  {
    protected synchronized void handleObj( Object obj )
    {
      synchronized( T1.class )
      {
        if ( ObjectHashCodeThreadMap.get( obj.hashCode() ) != null )
        {
          System.out.println( "T1-with-hashcode: " + obj + " duplicated. " );
          ++hashCodeDuplicates;
        }
        else
          ObjectHashCodeThreadMap.put( obj.hashCode(), (Long) Thread.currentThread().getId() );
      }
    }
  }

  //check with object, the object referenced.
  private static class T2 extends T
  {
    protected void handleObj( Object obj )
    {
      synchronized( T2.class )
      {
        if ( ObjectThreadMap.get( obj ) != null )
        {
          System.out.println( "T2-with-reference: " + obj + " duplicated. " );
          ++referenceDuplicates;
        }
        else
          ObjectThreadMap.put( obj, (Long) Thread.currentThread().getId() );
      }
    }
  }

  public static void main( String[] args )
  {
    System.out.println( "=============== tasks begin ================== ");
    
    for ( int i = 0; i < THREAD_NUM; i++ )
    {
      ( new T1() ).start();
      ( new T2() ).start();
      try
      {
        Thread.sleep( THREAD_TIME_SPAN );
      }
      catch( Exception e )
      {
      }
    }
    yield();
    
    System.out.println( "hashCodeDuplicates: " + hashCodeDuplicates );
    System.out.println( "referenceDuplicates: " + referenceDuplicates );
    System.out.println( "=============== tasks done ================== ");
  }

  public static void yield()
  {
    try
    {
      Thread.sleep( LOOP_TIMES*HOLD_TIME + THREAD_NUM*THREAD_TIME_SPAN + 1000 );
    }
    catch( Exception e )
    {
      System.out.println( e.toString() );
    }

    Thread.yield();
  }
}
